﻿using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using DrawingImaging = System.Drawing.Imaging;
using MediaImaging = System.Windows.Media.Imaging;

namespace Text_Grab.Models;

// from: https://github.com/microsoft/PowerToys/blob/7e4e8f59bb9468f7f8bb7183d861b3b47e67a1e5/src/modules/launcher/PowerLauncher/Helper/DragDataObject.cs
// based on: https://stackoverflow.com/questions/61041282/showing-image-thumbnail-with-mouse-cursor-while-dragging/61148788#61148788
public static class DragDataObject
{
    private static readonly Guid DataObject = new("b8c0bd9f-ed24-455c-83e6-d5390c4fe8c4");

    public static IDataObject FromFile(string filePath)
    {
        Marshal.ThrowExceptionForHR(SHCreateItemFromParsingName(filePath, null, typeof(IShellItem).GUID, out IShellItem item));
        Marshal.ThrowExceptionForHR(item.BindToHandler(null, DataObject, typeof(IDataObject).GUID, out object dataObject));
        return (IDataObject)dataObject;
    }

    public static void SetDragImage(this IDataObject dataObject, IntPtr hBitmap, int width, int height)
    {
        ArgumentNullException.ThrowIfNull(dataObject);

        IDragSourceHelper dragDropHelper = (IDragSourceHelper)new DragDropHelper();
        ShDragImage dragImage = new()
        {
            HBmpDragImage = hBitmap,
            SizeDragImage = new Size(width, height),
        };
        Marshal.ThrowExceptionForHR(dragDropHelper.InitializeFromBitmap(ref dragImage, dataObject));
    }

    [DllImport("shell32", CharSet = CharSet.Unicode)]
    private static extern int SHCreateItemFromParsingName(string path, IBindCtx? pbc, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IShellItem ppv);

    [Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    private interface IShellItem
    {
        [PreserveSig]
        int BindToHandler(IBindCtx? pbc, [MarshalAs(UnmanagedType.LPStruct)] Guid bhid, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out object ppv);

        // more methods available, but we don't need them
    }

    [ComImport]
    [Guid("4657278a-411b-11d2-839a-00c04fd918d0")] // CLSID_DragDropHelper
    private class DragDropHelper
    {
    }

    // https://learn.microsoft.com/windows/win32/api/shobjidl_core/ns-shobjidl_core-shdragimage
    [StructLayout(LayoutKind.Sequential)]
    private struct ShDragImage
    {
        public Size SizeDragImage;
        public Point PtOffset;
        public IntPtr HBmpDragImage;
        public int CrColorKey;
    }

    // https://learn.microsoft.com/windows/win32/api/shobjidl_core/nn-shobjidl_core-idragsourcehelper
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [Guid("DE5BF786-477A-11D2-839D-00C04FD918D0")]
    private interface IDragSourceHelper
    {
        [PreserveSig]
        int InitializeFromBitmap(ref ShDragImage pShDrawImage, IDataObject pDataObject);

        // more methods available, but we don't need them
    }

    // https://stackoverflow.com/a/2897325
    public static Bitmap? BitmapSourceToBitmap(MediaImaging.BitmapSource source)
    {
        if (source == null)
        {
            return null;
        }

        Bitmap bitmap = new(source.PixelWidth, source.PixelHeight, DrawingImaging.PixelFormat.Format32bppArgb);
        DrawingImaging.BitmapData bitmapData = bitmap.LockBits(new Rectangle(Point.Empty, bitmap.Size), DrawingImaging.ImageLockMode.WriteOnly, DrawingImaging.PixelFormat.Format32bppArgb);

        source.CopyPixels(System.Windows.Int32Rect.Empty, bitmapData.Scan0, bitmapData.Height * bitmapData.Stride, bitmapData.Stride);
        bitmap.UnlockBits(bitmapData);

        return bitmap;
    }
}